query-performance.tsx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { useParams } from 'common'
  2. import { parseAsArrayOf, parseAsInteger, parseAsJson, parseAsString, useQueryStates } from 'nuqs'
  3. import { Admonition } from 'ui-patterns'
  4. import { useIndexAdvisorStatus } from '@/components/interfaces/QueryPerformance/hooks/useIsIndexAdvisorStatus'
  5. import { useQueryPerformanceSort } from '@/components/interfaces/QueryPerformance/hooks/useQueryPerformanceSort'
  6. import { QueryPerformance } from '@/components/interfaces/QueryPerformance/QueryPerformance'
  7. import { type QuerySource } from '@/components/interfaces/QueryPerformance/QueryPerformance.types'
  8. import { useQueryPerformanceInfiniteQuery } from '@/components/interfaces/QueryPerformance/useQueryPerformanceQuery'
  9. import { PRESET_CONFIG } from '@/components/interfaces/Reports/Reports.constants'
  10. import { Presets } from '@/components/interfaces/Reports/Reports.types'
  11. import { queriesFactory } from '@/components/interfaces/Reports/Reports.utils'
  12. import { NumericFilter } from '@/components/interfaces/Reports/v2/ReportsNumericFilter'
  13. import { DefaultLayout } from '@/components/layouts/DefaultLayout'
  14. import ObservabilityLayout from '@/components/layouts/ObservabilityLayout/ObservabilityLayout'
  15. import { DatabaseSelector } from '@/components/ui/DatabaseSelector'
  16. import { DocsButton } from '@/components/ui/DocsButton'
  17. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  18. import { DOCS_URL } from '@/lib/constants'
  19. import type { NextPageWithLayout } from '@/types'
  20. const QueryPerformanceReport: NextPageWithLayout = () => {
  21. const { ref } = useParams()
  22. const { data: project, isLoading: isLoadingProject } = useSelectedProjectQuery()
  23. const { isIndexAdvisorEnabled } = useIndexAdvisorStatus()
  24. const { sort: sortConfig } = useQueryPerformanceSort()
  25. const [
  26. {
  27. search: searchQuery,
  28. roles,
  29. sources,
  30. minCalls,
  31. totalTimeFilter: totalTimeFilterRaw,
  32. indexAdvisor,
  33. },
  34. ] = useQueryStates({
  35. sort: parseAsString,
  36. order: parseAsString,
  37. search: parseAsString.withDefault(''),
  38. roles: parseAsArrayOf(parseAsString).withDefault([]),
  39. sources: parseAsArrayOf(parseAsString).withDefault([]),
  40. minCalls: parseAsInteger,
  41. totalTimeFilter: parseAsJson<NumericFilter | null>((value) =>
  42. value === null || value === undefined ? null : (value as NumericFilter)
  43. ),
  44. indexAdvisor: parseAsString.withDefault('false'),
  45. })
  46. const totalTimeFilter = totalTimeFilterRaw ?? null
  47. const config = PRESET_CONFIG[Presets.QUERY_PERFORMANCE]
  48. const hooks = queriesFactory(config.queries, ref ?? 'default')
  49. const queryHitRate = hooks.queryHitRate()
  50. const queryMetrics = hooks.queryMetrics()
  51. const minTotalTime =
  52. totalTimeFilter && totalTimeFilter.operator === '>'
  53. ? totalTimeFilter.value
  54. : totalTimeFilter && totalTimeFilter.operator === '>='
  55. ? totalTimeFilter.value
  56. : undefined
  57. const queryPerformanceQuery = useQueryPerformanceInfiniteQuery({
  58. searchQuery,
  59. orderBy: sortConfig || undefined,
  60. preset: 'unified',
  61. roles,
  62. sources: sources as QuerySource[],
  63. runIndexAdvisor: isIndexAdvisorEnabled,
  64. minCalls: minCalls ?? undefined,
  65. minTotalTime,
  66. filterIndexAdvisor: indexAdvisor === 'true',
  67. })
  68. if (!isLoadingProject && !project) {
  69. return (
  70. <div className="h-full flex flex-col p-6">
  71. <Admonition
  72. type="destructive"
  73. title="Project not found"
  74. description="Unable to load project data. Please check your project reference and try again."
  75. />
  76. </div>
  77. )
  78. }
  79. return (
  80. <div className="h-full flex flex-col">
  81. <div className="w-full mb-0 flex lg:items-center justify-between gap-4 py-4 px-6 lg:flex-row flex-col">
  82. <h3 className="text-foreground text-xl prose">Query Performance</h3>
  83. <div className="flex items-center gap-2 flex-wrap">
  84. <DocsButton
  85. href={`${DOCS_URL}/guides/platform/performance#examining-query-performance`}
  86. />
  87. <DatabaseSelector />
  88. </div>
  89. </div>
  90. <QueryPerformance
  91. queryHitRate={queryHitRate}
  92. queryPerformanceQuery={queryPerformanceQuery}
  93. queryMetrics={queryMetrics}
  94. />
  95. </div>
  96. )
  97. }
  98. QueryPerformanceReport.getLayout = (page) => (
  99. <DefaultLayout>
  100. <ObservabilityLayout title="Query Performance">{page}</ObservabilityLayout>
  101. </DefaultLayout>
  102. )
  103. export default QueryPerformanceReport